package bounce;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;



/**
 * Simple GUI program to show an animation of shapes. Class AnimationViewer is
 * a special kind of GUI component (JPanel), and as such an instance of 
 * AnimationViewer can be added to a JFrame object. A JFrame object is a 
 * window that can be closed, minimised, and maximised. The state of a
 * AnimationViewer object comprises a list of Shapes and a Timer object. An
 * AnimationViewer instance subcribes to events that are published by a Timer.
 * In response to receiving an event from the Timer, the AnimationViewer iterates 
 * through a list of Shapes requesting that each Shape paints and moves itself.
 * 
 * @author Ian Warren
 */
public class AnimationViewer extends JPanel implements ActionListener {
	// Frequency in milliseconds to generate ActionEvents.
	private final int DELAY = 20;

	// Collection of Shapes to animate.
	private List<Shape> shapes;

	private Timer timer = new Timer(DELAY, this);

	/**
	 * Creates an AnimationViewer instance with a list of Shape objects and 
	 * starts the animation.
	 */
	public AnimationViewer() {
		shapes = new ArrayList<Shape>();
	
		// Populate the list of Shapes.
		/*shapes.add(new RectangleShape(0, 0, 2, 3));
		shapes.add(new RectangleShape(10, 10, 5, 7));
		shapes.add(new GemShape(0, 0, 2, 3, 70, 70));*/
		
		//shapes.add(new RectangleTextShape(50, 50, 1, 5, 25, 50, "hello world"));
		
		Color c = new Color(150, 150, 0); //light green
		DynamicRectangleShape green = new DynamicRectangleShape(20, 20, 2, 3, 20, 30, c);
		
		c = new Color(200, 0, 200); //purple
		DynamicRectangleShape purple = new DynamicRectangleShape(30, 30, 2, 2, 30, 20, c);
		
		NestingShape smallNest = new NestingShape(50, 50, 1, 2, 100, 100);
		smallNest.add(green);
		smallNest.add(purple);
		
		BorderShape one = new BorderShape(smallNest);
		//shapes.add(one);
		
		RectangleTextShape text = new RectangleTextShape(50, 50, 3, 5, 80, 40, "hello world");
		
		NestingShape largeNest = new NestingShape(100, 100, 2, 1, 300, 300);
		largeNest.add(smallNest);
		largeNest.add(text);
		largeNest.add(one);
		shapes.add(largeNest);
		
		BorderShape two = new BorderShape(largeNest);
		shapes.add(two);
		
		BorderShape three = new BorderShape(two);
		shapes.add(three);
		
		// Start the animation.
		timer.start();
	}

	/**
	 * Called by the Swing framework whenever this AnimationViewer object
	 * should be repainted. This can happen, for example, after an explicit 
	 * repaint() call or after the window that contains this AnimationViewer 
	 * object has been exposed after being hidden by another window. 
	 * 
	 */
	public void paintComponent(Graphics g) {
		// Call inherited implementation to handle background painting.
		super.paintComponent(g);
		
		// Calculate bounds of animation screen area.
		int width = getSize().width;
		int height = getSize().height;
		
		// Create a GraphicsPainter that Shape objects will use for drawing.
		// The GraphicsPainter delegates painting to a basic Graphics object.
		Painter painter = new GraphicsPainter(g);
		
		// Progress the animation.
		for(Shape s : shapes) {
			s.paint(painter);
			s.move(width, height);
		}
	}

	/**
	 * Notifies this AnimationViewer object of an ActionEvent.
	 */
	public void actionPerformed(ActionEvent e) {
		// Request that the AnimationViewer repaints itself. The call to 
		// repaint() will cause the AnimationViewer's paintComponent() to be
		// called.
		repaint();
	}
	
	/**
	 * Main program method to create an AnimationViewer object and display this
	 * within a JFrame window.
	 */
	public static void main(String[] args) {
		JFrame frame = new JFrame("Animation viewer");
		frame.add(new AnimationViewer());
		
		// Set window properties.
		frame.setSize(500, 500);
		frame.setVisible(true);
		frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
	}
}
